
package com.videri.match.client;

import com.google.gwt.user.client.ui.*;
import com.google.gwt.core.client.*;
import com.google.gwt.user.client.rpc.*;
import com.google.gwt.user.client.Window;


/**
 * Sink for creating matching games.  Includes mode for specifying
 * image regions in the case of a text to image-region game.
 * @author Patrick Eibl
 *
 */
public class CreateGame extends MatchSink{
	
	public static MatchSinkInfo init(){
		return new MatchSinkInfo("Create New Matching") {
			public MatchSink createInstance(){
				return new CreateGame();
			}
			
			public String getColor(){
				// You can change this to change the color of the tab for this option
				return "#F19928";
			}
		};
	}

	private SimplePanel myRootPanel = new SimplePanel();
	private static final String ROOT_STYLE_NAME = "match-creategame";
	private static final String DEFAULT_IMAGE_URL = "http://www.theodora.com/maps/new5/usa_color.gif";
	private Label lbl = new Label();
	private boolean selecting = false;
	int startx, starty;  // The location of the mouse when the dragging started.
	int mousex, mousey;    // The location of the mouse during dragging.
	private Rectangle myNewest;
	private String myImageURL;
	private Image myImage;
	private Label myStatusBar = new Label();
	private final String DRAW_DIRECTIONS = "Click twice to define the corners of the matching region";
	private final String LABEL_DIRECTIONS = "Enter the label associated with this region";
	private VerticalPanel myMatchPanel;
	private PopupPanel mySelectedRegion = new PopupPanel(true);
	protected String myGameName;
	protected String myCategory;
	private VerticalPanel myGameConfigPanel = new VerticalPanel();
	private ListBox myGameTypeSelectList;
	private TextBox myURLBox;
	private int mySelectedGameType;
	
	public CreateGame(){
		initialize();
		initWidget(myRootPanel);
	}
	
	public void onModuleLoad() {
		initialize();
	}

	/**
	 * Switches to mode for specifying image regions
	 */
	private void makeTextToImageRegionGame() {
		myStatusBar.setText(DRAW_DIRECTIONS);
		myImage = new Image();
		HorizontalPanel panel = new HorizontalPanel();

		Button doneButton = new Button("Done", new ClickListener() {
			public void onClick(Widget sender) {
				done();
			}
		});
		
		Button showAllButton = new Button("Show All", new ClickListener() {
			public void onClick(Widget sender) {
				showAllRegions();
			}
		});
		HorizontalPanel doneAndShowAll = new HorizontalPanel();
		doneAndShowAll.add(doneButton);
		doneAndShowAll.add(showAllButton);
		myMatchPanel.add(doneAndShowAll);

		// Hook up a load listener, so that we can be informed if the image fails
		// to load.
		myImage.addLoadListener(new LoadListener() {
			public void onError(Widget sender) {
				lbl.setText("An error occurred while loading.");
			}

			public void onLoad(Widget sender) {
			}
		});

		// Point the image at a real URL.
		myImage.setUrl(myImageURL);

		myImage.addMouseListener(new MouseListener() {

			public void onMouseDown(Widget sender, int x, int y) {
				selecting = !selecting;
				if(selecting) {
					startx = x;
					starty = y;
					Rectangle rect = new Rectangle(x,y,x,y);
					mySelectedRegion.setPopupPosition(rect.x + myImage.getAbsoluteLeft(), rect.y + myImage.getAbsoluteTop());
					HTMLTable contents = new Grid(1,1);
					contents.setBorderWidth(1);
					contents.setPixelSize(rect.w, rect.h);
					mySelectedRegion.setWidget(contents);
					mySelectedRegion.show();
				}
				else {
					myNewest = new Rectangle(startx, starty, x, y);
					showRegion(myNewest);
					InputLabel il = new InputLabel(CreateGame.this);
					il.setPopupPosition(x + myImage.getAbsoluteLeft(), y);
					il.show();
					myStatusBar.setText(LABEL_DIRECTIONS);
				}
				//				myBoxText += "Mouse down at (" + x + "," + y + ")\n";
//				myTextArea.setText(myBoxText);
			}

			public void onMouseEnter(Widget sender) {}

			public void onMouseLeave(Widget sender) {}

			public void onMouseMove(Widget sender, int x, int y) {
				if(selecting) {
					myStatusBar.setText("Corners are (" + startx + "," + starty + ") and ("+ x + "," + y + ")");
					updateSelectedRegion(new Rectangle(startx,starty,x,y));
				}
			}

			public void onMouseUp(Widget sender, int x, int y) {
//				selecting = false;
//				myRectangles.add(new Rectangle(startx, starty, x, y));
//				myBoxText += "Your corners are (" + startx + "," + starty + "), (" + x + "," + y + ")\n";
//				myTextArea.setText(myBoxText);
			}

		});

		// Add the image, label, and clip/restore buttons to the root panel.
		VerticalPanel imagePanel = new VerticalPanel();
		imagePanel.add(myImage);
		imagePanel.add(myStatusBar);
//		panel.add(myTextArea);
		panel.add(myMatchPanel);
		panel.add(imagePanel);
		panel.add(lbl);
		
		myRootPanel.add(panel);
	}

	/**
	 * Shows all the regions thus far selected
	 */
	protected void showAllRegions() {
		MatchWidget mw;
		for(int i=1; i < myMatchPanel.getWidgetCount(); i++) {
			mw = (MatchWidget) myMatchPanel.getWidget(i);
			showRegion(mw.getRegion());
		}
	}

	/**
	 * Used to change area of table used to show region
	 * being selected
	 * @param rectangle
	 */
	protected void updateSelectedRegion(Rectangle rectangle) {
		mySelectedRegion.setPopupPosition(rectangle.x + myImage.getAbsoluteLeft(), rectangle.y + myImage.getAbsoluteTop());
		mySelectedRegion.getWidget().setPixelSize(rectangle.w,rectangle.h);		
	}

	/**
	 * Initializes this sink
	 */
	private void initialize() {
		myRootPanel.addStyleName(ROOT_STYLE_NAME);
		
		myMatchPanel = new VerticalPanel();
		myMatchPanel.setWidth("268px");
		VerticalPanel vp = new VerticalPanel();

		vp.add(new Label("Enter Game Name"));
		final TextBox gameNameBox = new TextBox();
		gameNameBox.setWidth("50em");
		gameNameBox.setText("New Game");
		vp.add(gameNameBox);
		
		vp.add(new Label("Enter Game Category"));
		final TextBox catBox = new TextBox();
		catBox.setWidth("50em");
		catBox.setText("Fun Games");
		vp.add(catBox);
		
		mySelectedGameType = 0;
		vp.add(new Label("Select Game Type"));
		myGameTypeSelectList = new ListBox();
		myGameTypeSelectList.setVisibleItemCount(1);
		myGameTypeSelectList.addItem("Text-Text");
		myGameTypeSelectList.addItem("Text-Image Regions");
		myGameTypeSelectList.addItem("Text-Images");
		vp.add(myGameTypeSelectList);
		
		vp.add(myGameConfigPanel);
		
		setGameConfigPanel();
//		Label urlLabel = new Label("Enter URL of Image");
//		vp.add(urlLabel);
//		final TextBox urlBox = new TextBox();
//		urlBox.setWidth("50em");
//		urlBox.setText(DEFAULT_IMAGE_URL);
//		vp.add(urlBox);
		
		myGameTypeSelectList.addChangeListener(new ChangeListener() {
			public void onChange(Widget sender) {
				mySelectedGameType = myGameTypeSelectList.getSelectedIndex();
				setGameConfigPanel();
			}	
		});
		
		Button makeGameButton = new Button("Make Game");
		makeGameButton.addClickListener(new ClickListener(){
			public void onClick(Widget sender) {
				myGameName = gameNameBox.getText();
				myCategory = catBox.getText();
				switch(mySelectedGameType) {
				case 0: //text-text
					if(isValidTextGame()) done();
					else Window.alert("One or more entries are empty!");
					break;
				case 1: //text-image region
					myImageURL = myURLBox.getText();
					myRootPanel.clear();
					makeTextToImageRegionGame();
					break;
				case 2: //text-images
					if(isValidTextGame()) done();
					else Window.alert("One or more entries are empty!");
					break;
				}
			}
		});
		vp.add(makeGameButton);
		myRootPanel.add(vp);
	}

	/**
	 * Changes the game configuration panel based on what is chosen
	 * from the drop box.
	 */
	private void setGameConfigPanel() {
		myGameConfigPanel.clear();
		switch(mySelectedGameType) {
		case 0: //text-text
			HorizontalPanel buttons = new HorizontalPanel();
			Button addPair = new Button("Add Pair");
			addPair.addClickListener(new ClickListener() {
				public void onClick(Widget sender) {
					addTextPair();
				}
			});
			buttons.add(addPair);
			
			Button removePair = new Button("Remove Pair");
			removePair.addClickListener(new ClickListener() {
				public void onClick(Widget sender) {
					removeTextPair();
				}
			});
			buttons.add(removePair);
			myGameConfigPanel.add(buttons);
			for(int i=0; i<3; i++) addTextPair();
			break;
		case 1: //text-image region
			Label urlLabel = new Label("Enter URL of Image");
			myGameConfigPanel.add(urlLabel);
			myURLBox = new TextBox();
			myURLBox.setWidth("50em");
			myURLBox.setText(DEFAULT_IMAGE_URL);
			myGameConfigPanel.add(myURLBox);
			break;
		case 2: //text-images
			HorizontalPanel labels = new HorizontalPanel();
			Label text = new Label("Text");
			text.setWidth("25em");
			text.setHorizontalAlignment(Label.ALIGN_LEFT);
			Label url = new Label("URL of Image");
			url.setWidth("15em");
			url.setHorizontalAlignment(Label.ALIGN_RIGHT);
			labels.add(text);
			labels.add(url);
			myGameConfigPanel.add(labels);
			
			HorizontalPanel buttons2 = new HorizontalPanel();
			Button addPair2 = new Button("Add Pair");
			addPair2.addClickListener(new ClickListener() {
				public void onClick(Widget sender) {
					addTextPair();
				}
			});
			buttons2.add(addPair2);
			
			Button removePair2 = new Button("Remove Pair");
			removePair2.addClickListener(new ClickListener() {
				public void onClick(Widget sender) {
					removeTextPair();
				}
			});
			buttons2.add(removePair2);
			myGameConfigPanel.add(buttons2);
			for(int i=0; i<3; i++) addTextPair();
			break;
		}
	}
	
	/**
	 * Adds a text pair to the list
	 */
	private void addTextPair() {
		HorizontalPanel hp = new HorizontalPanel();
		TextBox from = new TextBox();
		from.setWidth("15em");
		TextBox to = new TextBox();
		to.setWidth("15em");
		hp.add(from);
		Label matches = new Label(" matches to ");
		matches.setWidth("10em");
		matches.setHorizontalAlignment(Label.ALIGN_CENTER);
		hp.add(matches);
		hp.add(to);
		myGameConfigPanel.insert(hp, myGameConfigPanel.getWidgetCount()-1);		
	}
	
	/**
	 * Removes a text pair, unless there's only one left
	 */
	private void removeTextPair() {
		int matchCount = myGameConfigPanel.getWidgetCount();
		switch(mySelectedGameType) {
		case 0:
			if(matchCount>2) myGameConfigPanel.remove(matchCount-2);
			break;
		case 2:
			if(matchCount>3) myGameConfigPanel.remove(matchCount-2);
			break;
		}
	}
	
	/**
	 * Checks if any boxes are empty
	 * @return true if no empty boxes
	 */
	boolean isValidTextGame() {
		//get data of matchings from myGameConfigPanel
		int matchCount = myGameConfigPanel.getWidgetCount()-1;
		HorizontalPanel current;
		int start=0;
		switch(mySelectedGameType) {
		case 0: start=0; break;
		case 2: start=1; break;
		}
		for(int i=start; i< matchCount; i++) {
			current = (HorizontalPanel) myGameConfigPanel.getWidget(i);
			if(((TextBox)current.getWidget(0)).getText().equals("")) return false;
			if(((TextBox)current.getWidget(2)).getText().equals("")) return false;
		}
		return true;
	}
	
	/**
	 * Changes the screen, collects the data and sends matching
	 * to the server
	 */
	private void done() {
		//status screen when done
		myRootPanel.clear();
		final Label l = new Label();
		VerticalPanel vp = new VerticalPanel();
		vp.add(l);
		l.setText("Waiting for callback");
		vp.add(new Button("Create Another", new ClickListener() {
			public void onClick(Widget sender) {
				myRootPanel.clear();
				lbl = new Label();
				initialize();
			}
		}));
		myRootPanel.add(vp);
		
		Matching matching;
		switch(mySelectedGameType) {
		case 0:
			//get data of matchings from myGameConfigPanel
			int matchCount = myGameConfigPanel.getWidgetCount()-1;
			String[] items1 = new String[matchCount], items2 = new String[matchCount];
			HorizontalPanel current;
			for(int i=0; i< matchCount; i++) {
				current = (HorizontalPanel) myGameConfigPanel.getWidget(i);
				items1[i] = ((TextBox)current.getWidget(0)).getText();
				items2[i] = ((TextBox)current.getWidget(2)).getText();
			}
			matching = new Matching(myGameName,items1,items2);
			break;
		case 1:
			//get data of matchings from myMatchPanel
			MatchWidget mw;
			String[] names = new String[myMatchPanel.getWidgetCount()-1];
			Rectangle[] regions = new Rectangle[myMatchPanel.getWidgetCount()-1];
			for(int i=1; i < myMatchPanel.getWidgetCount(); i++) {
				mw = (MatchWidget) myMatchPanel.getWidget(i);
				names[i-1] = mw.getLabel();
				regions[i-1] = mw.getRegion();
			}

			//Server stuff
			matching = new Matching(myGameName,names,regions,myImage);
			break;
		case 2:
			//get data of matchings from myGameConfigPanel
			int matchCount2 = myGameConfigPanel.getWidgetCount()-2;
			String[] items12 = new String[matchCount2];
			Image[] images2 = new Image[matchCount2];
			HorizontalPanel current2;
			for(int i=1; i< matchCount2+1; i++) {
				current2 = (HorizontalPanel) myGameConfigPanel.getWidget(i);
				items12[i-1] = ((TextBox)current2.getWidget(0)).getText();
				images2[i-1] = new Image(((TextBox)current2.getWidget(2)).getText());
			}
			matching = new Matching(myGameName,items12,images2);
			break;
		default:
			System.err.println("Bad game type index");
			matching = null;
			break;
		}

	
		//This is the awesome code right here!!!
		VideriMatchServiceAsync videriServices = (VideriMatchServiceAsync)GWT.create(VideriMatchService.class);
		
		  ServiceDefTarget endpoint = (ServiceDefTarget) videriServices;
		  String moduleRelativeURL = GWT.getModuleBaseURL()+"matching";
		  endpoint.setServiceEntryPoint(moduleRelativeURL);
		
		AsyncCallback callback = new AsyncCallback() {                
			public void onSuccess(Object result) {
				//myStatusBar.setText("Matching Game Created!");      
				l.setText("Matching Game Created");
			}                
			public void onFailure(Throwable caught) {                    
				l.setText("Error Creating Matching Game!");              
			}            
		};
		videriServices.addNewMatching(matching, myCategory, callback);
	}

	/**
	 * The popup that you enter labels for image regions in
	 * @author Patrick Eibl
	 *
	 */
	private class InputLabel extends PopupPanel {
		public InputLabel(final CreateGame m) {
			super(false);

			final TextBox inputBox = new TextBox();
			inputBox.setWidth("20em");
			inputBox.addKeyboardListener(new KeyboardListener() {
				public void onKeyDown(Widget sender, char keyCode,
						int modifiers) {
					if (keyCode == KeyboardListener.KEY_ENTER) {
						m.processLabelInput(inputBox.getText());
						hide();
					}
				}

				public void onKeyPress(Widget sender, char keyCode,
						int modifiers) {}

				public void onKeyUp(Widget sender, char keyCode,
						int modifiers) {}

			});

			setWidget(inputBox);
		}
	}
	
	/**
	 * The widgets that go in the left panel when
	 * creating a text-image region game
	 * @author Patrick Eibl
	 *
	 */
	private class MatchWidget extends HorizontalPanel {
		private Rectangle myRectangle;//used for showing
		private Button myShowButton, myRemoveButton;
		private Label myLabel;
		public MatchWidget(String label, Rectangle rect) {
			myLabel = new Label(label);
			myLabel.setWidth("10em");
			add(myLabel);
			myRectangle = rect;
			createButtons();
			add(myShowButton);
			add(myRemoveButton);
		}
		private void createButtons() {
			myShowButton = new Button("Show");
			myRemoveButton = new Button("Remove");
			myShowButton.addClickListener(new ClickListener() {
				public void onClick(Widget sender) {
					showRegion(myRectangle);
				}
			});
			myRemoveButton.addClickListener(new ClickListener() {
				public void onClick(Widget sender) {
					removeMatch(MatchWidget.this);
				}
			});
		}
		public String getLabel() {return myLabel.getText();}
		public Rectangle getRegion() {return myRectangle;}
	}
	
	/**
	 * Shows the region indicated by the parameter
	 * @param rect
	 */
	protected void showRegion(Rectangle rect) {
		PopupPanel p = new PopupPanel(true);
		p.setPopupPosition(rect.x + myImage.getAbsoluteLeft(), rect.y + myImage.getAbsoluteTop());
		HTMLTable contents = new Grid(1,1);
		contents.setBorderWidth(1);
		contents.setPixelSize(rect.w, rect.h);
		p.setWidget(contents);
		p.show();
	}
	
	/**
	 * Removes the specified MatchWidget from myMatchPanel
	 * @param mw
	 */
	public void removeMatch(MatchWidget mw) {
		myMatchPanel.remove(mw);
	}

	/**
	 * Called after label is entered for an image region
	 * @param text
	 */
	protected void processLabelInput(String text) {
		//myBoxText += "Your corners are (" + startx + "," + starty + "), (" + x + "," + y + ")\n";
//		myBoxText += text + ":  (" + myNewest.x+','+myNewest.y+','+myNewest.w+','+myNewest.h+")\n";
		myStatusBar.setText(DRAW_DIRECTIONS);
		myMatchPanel.add(new MatchWidget(text,myNewest));
	}
}
